package com.loyal.camerax.ui.base

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.setPadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.loyal.camerax.R
import com.loyal.camerax.databinding.CameraUiContainerBinding
import com.loyal.camerax.databinding.CameraUiSettingsBinding
import com.loyal.camerax.databinding.FragmentCameraBinding
import com.loyal.camerax.impl.CameraConfigCallback
import com.loyal.camerax.impl.PicturePreviewCallback
import com.loyal.camerax.ui.CameraViewModel
import com.loyal.camerax.ui.camera.CameraFragmentActivity
import com.loyal.camerax.ui.camera.CameraFragmentDirections
import com.loyal.camerax.ui.settings.CameraSettingsActivity
import com.loyal.camerax.utils.ActivityHelper.hasPermissions
import com.loyal.camerax.utils.KEY_EVENT_ACTION
import com.loyal.camerax.utils.KEY_EVENT_EXTRA
import com.loyal.camerax.utils.MediaStoreUtils
import com.loyal.camerax.utils.PermissionHelper
import com.loyal.camerax.utils.PreferenceHelper
import com.loyal.camerax.utils.delayClick
import com.loyal.camerax.utils.simulateClick
import com.loyal.camerax.view.TorchFlashMenu
import kotlinx.coroutines.launch

abstract class BaseCameraFragment : Fragment(), PicturePreviewCallback, CameraConfigCallback {
    private var _binding: FragmentCameraBinding? = null
    protected val binding get() = _binding!!
    private val settingsBinding by lazy { binding.settingsPanel }
    private val cameraBinding by lazy { binding.cameraPanel }

    private lateinit var broadcastManager: LocalBroadcastManager
    private val mediaStoreUtils by lazy { MediaStoreUtils(requireContext()) }

    private var settingsLauncher: ActivityResultLauncher<Intent>? = null
    private val cameraViewModel: CameraViewModel by activityViewModels()

    private val volumeDownReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.getIntExtra(KEY_EVENT_EXTRA, KeyEvent.KEYCODE_UNKNOWN)) {
                KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> {
                    binding.cameraPanel.cameraCapture.simulateClick()
                }
            }
        }
    }

    fun settingsBinding(): CameraUiSettingsBinding {
        return settingsBinding
    }

    protected open fun orientationMutable(): Boolean {
        return activity?.intent?.getBooleanExtra(PreferenceHelper.MUTABLE_ORIENTATION, false)
            ?: false
    }

    fun cameraBinding(): CameraUiContainerBinding {
        return cameraBinding
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCameraBinding.inflate(inflater, container, false)

        settingsLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
                val action = it.data?.action
                if (PreferenceHelper.KEY_RESTART_ACTION == action) {
                    restart(this)
                }
            }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initCamerax()
        initBroadcast()
    }

    private fun initBroadcast() {
        broadcastManager = LocalBroadcastManager.getInstance(requireContext())
        val filter = IntentFilter().apply { addAction(KEY_EVENT_ACTION) }
        broadcastManager.registerReceiver(volumeDownReceiver, filter)
    }

    protected fun setCameraUI() {
        lifecycleScope.launch {
            val thumbnailUri = mediaStoreUtils.getLatestImageFilename()
            thumbnailUri?.let {
                setGalleryThumbnail(it)
            }
        }

        binding.settingsPanel.apply {
            flashSwitch.setOnClickListener {
                it.delayClick()
                switchFlash(flashSwitch)
            }
            cameraSetting.setOnClickListener {
                it.delayClick()
                CameraSettingsActivity.launch(
                    requireActivity(), settingsLauncher,
                    R.id.settings_fragment, orientationMutable()
                )
            }
        }

        binding.cameraPanel.apply {
            cameraCapture.setOnClickListener {
                takePhoto()
            }
            cameraGallery.setOnClickListener {
                openGallery()
            }
            cameraGallery.setOnLongClickListener {
                it.tag = null
                cameraGallery.setImageResource(R.drawable.ic_photo)
                true
            }

            cameraSwitch.setOnClickListener {
                it.delayClick()
                switchCamera()
            }
        }
    }

    protected fun setGalleryThumbnail(filename: String) {
        binding.cameraPanel.cameraGallery.let { photoViewButton ->
            photoViewButton.post {
                photoViewButton.setPadding(resources.getDimension(R.dimen.stroke_small).toInt())

                Glide.with(photoViewButton)
                    .load(filename)
                    .apply(RequestOptions.circleCropTransform())
                    .into(photoViewButton)
            }
        }
    }

    override fun savePath(): String {
        return ""
    }

    override fun saveName(): String {
        return ""
    }

    protected open fun switchFlash(flashView: ImageButton) {
        if (null == popupMenu)
            intiFlashMenu(flashView)
        popupMenu?.show()
    }

    private var popupMenu: TorchFlashMenu? = null

    private fun intiFlashMenu(flashView: ImageButton) {
        popupMenu = TorchFlashMenu(requireContext(), flashView)
        popupMenu?.setOnTorchFlashChangedListener(object :
            TorchFlashMenu.OnTorchFlashChangedListener {
            override fun onTouchFlashChanged(state: String): Boolean {
                return updateTorchFlash(flashView, state)
            }
        })
    }

    override fun openGallery() {
        val tag = cameraBinding().cameraGallery.tag as? String?
        tag?.let {

        }
        activity?.let {
            CameraSettingsActivity.launch(
                it, settingsLauncher, R.id.gallery_fragment
            )
        }
    }

    override fun onResume() {
        super.onResume()
        cameraViewModel.updateStatus(javaClass.hashCode())
        if (!requireContext().hasPermissions(PermissionHelper.all())) {
            val action = CameraFragmentDirections.actionToPermissions()
            findNavController().navigate(action)
        }
    }

    override fun onPause() {
        super.onPause()
        cameraViewModel.updateStatus(javaClass.hashCode())
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        Log.e(TAG, "onConfigurationChanged: ")
        // Rebind the camera with the updated display metrics
        //bindCameraUseCases()

        // Enable or disable switching between cameras
        //updateCameraSwitchButton()
    }

    protected open fun restart(fragment: Fragment) {
        Log.e(TAG, "restart: ")
        fragment.activity?.apply {
            val paramsIntent = this.intent
            val restartIntent = Intent(
                this, CameraFragmentActivity::class.java
            )
            paramsIntent?.let {
                restartIntent.putExtras(it)
            }
            this.startActivity(restartIntent)
            this.finish()
        }
    }

    override fun onDestroyView() {
        _binding = null
        super.onDestroyView()
        broadcastManager.unregisterReceiver(volumeDownReceiver)
    }

    companion object {
        private const val TAG = "BaseCameraFragment"

    }
}